﻿Imports System.Collections.ObjectModel
Imports System.Runtime.Serialization

''' <summary>
''' Stores a table of chars and ranges and provides fast searching for matched char or range
''' </summary>
''' <remarks></remarks>
<DataContract(Name:="CharIndexTableOf{0}", namespace:="urn:VBF.CompilerModel.Scanner")>
Public Class CharIndexTable(Of T)
    Const c_OptRange As Integer = 127

    <DataMember(name:="OptimizedTable")>
    Private m_optTable As OptimizedCharTable
    <DataMember(name:="RuleTable")>
    Private m_ruleTable As RuleMatchTable

    Public Sub New()
        m_optTable = New OptimizedCharTable
        m_ruleTable = New RuleMatchTable
    End Sub

    Public Function Match(ByVal c As Char) As T
        If AscW(c) > c_OptRange Then
            Return m_ruleTable.Match(c)
        Else
            Return m_optTable.Match(c)
        End If
    End Function

    Public Sub Add(ByVal c As Char, ByVal match As T)
        If AscW(c) > c_OptRange Then
            m_ruleTable.Register(c, match)
        Else
            m_optTable.Register(c, match)
        End If
    End Sub

    Public Sub Add(ByVal range As CharRange, ByVal match As T)
        If AscW(range.Min) > c_OptRange Then
            m_ruleTable.Register(range, match)
        ElseIf AscW(range.Min) <= c_OptRange AndAlso AscW(range.Max) > c_OptRange Then
            m_ruleTable.Register(New CharRange(ChrW(c_OptRange + 1), range.Max), match)
            m_optTable.Register(New CharRange(range.Min, ChrW(c_OptRange)), match)
        Else
            m_optTable.Register(range, match)
        End If
    End Sub

    ''' <summary>
    ''' An optimized table for chars between 0-255
    ''' </summary>
    <DataContract(Namespace:="urn:VBF.CompilerModel.Scanner")>
    Class OptimizedCharTable
        <DataMember(Name:="CharsTable")>
        Private m_CharsTable(0 To c_OptRange) As T
        Private m_comparer As IEqualityComparer(Of T) = EqualityComparer(Of T).Default

        Sub Register(ByVal c As Char, ByVal value As T)
            If m_comparer.Equals(m_CharsTable(AscW(c)), Nothing) Then m_CharsTable(AscW(c)) = value
        End Sub

        Sub Register(ByVal range As CharRange, ByVal value As T)
            For i = AscW(range.Min) To Math.Min(c_OptRange, AscW(range.Max))
                If m_comparer.Equals(m_CharsTable(i), Nothing) Then m_CharsTable(i) = value
            Next
        End Sub

        Function Match(ByVal c As Char) As T
            Return m_CharsTable(AscW(c))
        End Function
    End Class

    <DataContract(Namespace:="urn:VBF.CompilerModel.Scanner")>
    Class RuleMatchTable
        <DataMember(Name:="RulesTable")>
        Private m_rules As List(Of Tuple(Of CharRange, T))
        Private m_comparer As IEqualityComparer(Of T) = EqualityComparer(Of T).Default

        Sub New()
            m_rules = New List(Of Tuple(Of CharRange, T))
        End Sub

        Sub Register(ByVal c As Char, ByVal value As T)
            m_rules.Add(Tuple.Create(New CharRange(c, c), value))
        End Sub

        Sub Register(ByVal range As CharRange, ByVal value As T)
            m_rules.Add(Tuple.Create(range, value))
        End Sub

        Function Match(ByVal c As Char) As T
            For Each rule In m_rules
                If c >= rule.Item1.Min AndAlso c <= rule.Item1.Max Then
                    Return rule.Item2
                End If
            Next

            Return Nothing
        End Function
    End Class
End Class

